package com.oak.broke.config.mybatis.encript;

import com.oak.broke.config.mybatis.encript.encrypt.ProcessEncrypt;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

/**
 * 数据库返回解密拦截器
 * @author DELL
 */
@Intercepts({@Signature(
        type = ResultSetHandler.class,
        method = "handleResultSets",
        args = {Statement.class}
)})
@Component
public class ResultDecryptInterceptor implements Interceptor {
    @Autowired
    private ProcessEncrypt processEncrypt;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Statement stmt = (Statement) invocation.getArgs()[0];
        ResultSet rs = stmt.getResultSet();
        Statement stmtProxy = (Statement) Proxy.newProxyInstance(Statement.class.getClassLoader(), new Class[]{Statement.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if ("getResultSet".equals(method.getName())) {
                    return Proxy.newProxyInstance(ResultSet.class.getClassLoader(), new Class[]{ResultSet.class}, new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            if (method.getName().startsWith("get")) {
                                Class[] clazzes = method.getParameterTypes();
                                if (clazzes.length == 1 && String.class.equals(clazzes[0])) {
                                    Object obj = method.invoke(rs, args);
                                    obj = processEncrypt.processDecrypt(args[0].toString(), obj);
                                    return obj;
                                }
                            }
                            return method.invoke(rs, args);
                        }
                    });
                }
                return method.invoke(stmt, args);
            }
        });
        return invocation.getMethod().invoke(invocation.getTarget(), stmtProxy);
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
